from math import asin, sin, cos, pow, sqrt, pi
from concurrent.futures import ThreadPoolExecutor
from flask import send_file
# from crypto import JWT

class MyTools():
    __slots__ = ('__THREAD_POOL')
    
    @classmethod
    def setup(cls):
        cls.__THREAD_POOL = ThreadPoolExecutor(max_workers=20)
    @classmethod
    def getDistance(cls, lng1, lat1, lng2, lat2):
        EARTH_REDIUS = 6378.137
        rad = pi / 180.0
        radLng1 = lng1 * rad
        radLng2 = lng2 * rad
        a = radLng1 - radLng2
        b = lat1 * rad - lat2 * rad
        s = 2 * asin(sqrt(pow(sin(a/2), 2) + cos(radLng1) * cos(radLng2) * pow(sin(b/2), 2)))

        return s * EARTH_REDIUS * 1000
    @classmethod
    def getThreadPoolExe(cls):
        return cls.__THREAD_POOL
    
    @classmethod
    def execute_with_retry(method, max_retries=3):
        retries = 0
        while retries < max_retries:
            result = method()
            if result:
                return result
            retries += 1

        return False

class EncryptionTool():
    __slots__ = ('__aes')
    __libs_crypto_cipher = __import__('Crypto.Cipher', fromlist=['AES'])
    __libs_crypto_util_padding = __import__('Crypto.Util.Padding', fromlist=['pad', 'unpad'])
    __libs_base64 = __import__('base64')
    __lib_crypto = __import__('Crypto.PublicKey', fromlist=['RSA'])

    @classmethod
    def generateRSAKeys(cls):
        key_val = cls.__lib_crypto.RSA.generate(2048)
        return (key_val.exportKey("PEM"), key_val.publickey().exportKey())      # 私钥，公钥
    @classmethod
    def initAES(cls, key):
        cls.__aes = cls.__libs_crypto_cipher.AES.new(key, cls.__libs_crypto_cipher.AES.MODE_ECB)
    @classmethod
    def encryptAES(cls, plaintext):
        pad_pkcs7 = cls.__libs_crypto_util_padding.pad(plaintext.encode('utf-8'), cls.__libs_crypto_cipher.AES.block_size)
        encrypt_data = cls.__aes.encrypt(pad_pkcs7)
        encr_data = str(cls.__libs_base64.b64encode(encrypt_data), encoding='utf-8')
        return encr_data
    @classmethod
    def decryptAES(cls, encr_data):
        padded_data = cls.__aes.decrypt(cls.__libs_base64.b64decode(encr_data.encode('utf-8')))
        return str(cls.__libs_crypto_util_padding.unpad(padded_data, cls.__libs_crypto_cipher.AES.block_size), encoding='utf-8')

class FS():
    __slots__ = ()
    __lib_isfile = __import__('genericpath', fromlist=['isfile'])
    __lib_os = __import__('os', fromlist=['unlink', 'path'])
    __lib_uuid1 = __import__('uuid', fromlist=['uuid1'])

    @classmethod
    def writeFile(cls, fpn, content, wtype='w+'):
        with open(fpn, wtype, encoding='utf-8') as f:
            f.write(content)
    @classmethod
    def delFile(cls, fn:str):
        if cls.__lib_isfile.isfile(fn): cls.__lib_os.unlink(fn)
    @classmethod
    def upload(cls, files, uppath):
        fns = []
        for f in files:
            fn = cls.__lib_uuid1.uuid1().hex + cls.__lib_os.path.splitext(f.filename)[-1]
            f.save(uppath + fn)
            fns.append(fn)
        return fns
    @classmethod
    def download(cls, fp):
        print(fp)
        return send_file(fp, as_attachment=True)
    

